﻿using System;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using Transfer.Utils;

namespace HyDrawSelectArea
{
	public class SelAreaEdgeInfo
	{
		public XYZ StartPoint { get; set; }

		public XYZ EndPoint { get; set; }

		public double Bulge { get; set; }

		public bool IsArc
		{
			get
			{
				return !Geometry.IsEqual(this.Bulge, 0.0);
			}
		}

		public XYZ Center
		{
			get
			{
				if (Geometry.IsEqual(this.Bulge, 0.0))
				{
					return null;
				}
				XYZ result = null;
				Geometry.GetCenterWithBulge(this.StartPoint, this.EndPoint, this.Bulge, ref result);
				return result;
			}
		}

		public bool IsPoint
		{
			get
			{
				return this.StartPoint.IsAlmostEqualTo(this.EndPoint);
			}
		}

		public double Radius
		{
			get
			{
				return this.StartPoint.DistanceTo(this.Center);
			}
		}

		public XYZ Normal
		{
			get
			{
				XYZ xyz;
				if (this.IsArc)
				{
					xyz = XYZ.BasisZ;
					if (Geometry.LessThan(this.Bulge, 0.0))
					{
						xyz = -xyz;
					}
				}
				else
				{
					xyz = (this.EndPoint - this.StartPoint).Normalize();
				}
				return xyz;
			}
		}

		public bool IsNull()
		{
			return this.StartPoint == null || this.EndPoint == null;
		}

		public SelAreaEdgeInfo(SelAreaEdgeInfo rhs)
		{
			this.StartPoint = rhs.StartPoint;
			this.EndPoint = rhs.EndPoint;
			this.Bulge = rhs.Bulge;
		}

		public SelAreaEdgeInfo(XYZ startPoint, XYZ endPoint, double bulge)
		{
			this.StartPoint = startPoint;
			this.EndPoint = endPoint;
			this.Bulge = bulge;
		}

		public SelAreaEdgeInfo(Curve curve, bool isKeepClockwiseDirectionWithArc = false)
		{
			if (curve.GetType() == typeof(Line))
			{
				this.StartPoint = SelAreaEdgeInfo.Get2DXYZ(curve.GetEndPoint(0));
				this.EndPoint = SelAreaEdgeInfo.Get2DXYZ(curve.GetEndPoint(1));
				this.Bulge = 0.0;
				return;
			}
			if (curve.GetType() == typeof(Arc))
			{
				Arc arc = curve as Arc;
				this.StartPoint = SelAreaEdgeInfo.Get2DXYZ(curve.GetEndPoint(0));
				this.EndPoint = SelAreaEdgeInfo.Get2DXYZ(curve.GetEndPoint(1));
				if (isKeepClockwiseDirectionWithArc)
				{
					bool isAnticlockwise = true;
					if (!arc.Normal.IsAlmostEqualTo(XYZ.BasisZ))
					{
						isAnticlockwise = false;
					}
					this.Bulge = Geometry.GetBulge(this.StartPoint, this.EndPoint, SelAreaEdgeInfo.Get2DXYZ(arc.Center), isAnticlockwise);
					return;
				}
				if (!arc.Normal.IsAlmostEqualTo(XYZ.BasisZ))
				{
					this.StartPoint = SelAreaEdgeInfo.Get2DXYZ(curve.GetEndPoint(1));
					this.EndPoint = SelAreaEdgeInfo.Get2DXYZ(curve.GetEndPoint(0));
				}
				this.Bulge = Geometry.GetBulge(this.StartPoint, this.EndPoint, SelAreaEdgeInfo.Get2DXYZ(arc.Center), true);
			}
		}

		public SelAreaEdgeInfo TransformTo(Transform matrix)
		{
			XYZ startPoint = Geometry.TransformPoint(this.StartPoint, matrix);
			XYZ endPoint = Geometry.TransformPoint(this.EndPoint, matrix);
			return new SelAreaEdgeInfo(startPoint, endPoint, this.Bulge);
		}

		public void TransformSelf(Transform matrix)
		{
			this.StartPoint = Geometry.TransformPoint(this.StartPoint, matrix);
			this.EndPoint = Geometry.TransformPoint(this.EndPoint, matrix);
		}

		public SelAreaEdgeInfo ReverseTo()
		{
			return new SelAreaEdgeInfo(this.EndPoint, this.StartPoint, -this.Bulge);
		}

		public void ReverseSelf()
		{
			XYZ startPoint = this.StartPoint;
			this.StartPoint = this.EndPoint;
			this.EndPoint = startPoint;
			this.Bulge = -this.Bulge;
		}

		public Curve ConvertTo(Autodesk.Revit.ApplicationServices.Application app)
		{
			Curve result = null;
			if (this.IsNull())
			{
				return result;
			}
			XYZ xyz = SelAreaEdgeInfo.Get2DXYZ(this.StartPoint);
			XYZ xyz2 = SelAreaEdgeInfo.Get2DXYZ(this.EndPoint);
			if (xyz.IsAlmostEqualTo(xyz2))
			{
				return result;
			}
			if (this.IsArc)
			{
				XYZ xyz3 = null;
				double num = 0.0;
				double dSAngle = 0.0;
				double dEAngle = 0.0;
				Geometry.GetArcInfoWithBulge(xyz, xyz2, this.Bulge, ref xyz3, ref num, ref dSAngle, ref dEAngle);
				double angle = Geometry.BetweenTheAngles(dSAngle, dEAngle, true) / 2.0;
				XYZ xyz4 = XYZ.BasisZ;
				if (Geometry.LessThan(this.Bulge, 0.0))
				{
					xyz4 = -xyz4;
				}
				XYZ list = xyz - xyz3;
				XYZ radianPnt = xyz3 + Geometry.RotateTo(list, angle, xyz4);
				return app.CreatYJKArc(xyz, xyz2, radianPnt);
			}
			return YJKLineEx.YJKGetBound(xyz, xyz2);
		}

		public double Length()
		{
			if (this.IsArc)
			{
				XYZ xyz = null;
				Geometry.GetCenterWithBulge(this.StartPoint, this.EndPoint, this.Bulge, ref xyz);
				double num = xyz.DistanceTo(this.StartPoint);
				double angle = Geometry.getAngle(xyz, this.StartPoint);
				double angle2 = Geometry.getAngle(xyz, this.EndPoint);
				double num2 = Geometry.BetweenTheAngles(angle, angle2, true);
				if (Geometry.LessThan(this.Bulge, 0.0))
				{
					num2 = Geometry.BetweenTheAngles(angle2, angle, true);
				}
				return num2 * num;
			}
			return this.StartPoint.DistanceTo(this.EndPoint);
		}

		public double DistanceToStart(XYZ pt)
		{
			if (this.IsArc)
			{
				XYZ xyz = null;
				Geometry.GetCenterWithBulge(this.StartPoint, this.EndPoint, this.Bulge, ref xyz);
				double num = xyz.DistanceTo(this.StartPoint);
				double angle = Geometry.getAngle(xyz, this.StartPoint);
				double angle2 = Geometry.getAngle(xyz, pt);
				double num2 = Geometry.BetweenTheAngles(angle, angle2, true);
				if (Geometry.LessThan(this.Bulge, 0.0))
				{
					num2 = Geometry.BetweenTheAngles(angle2, angle, true);
				}
				return num2 * num;
			}
			return this.StartPoint.DistanceTo(pt);
		}

		protected static XYZ Get2DXYZ(XYZ point3d)
		{
			return new XYZ(point3d.X, point3d.Y, 0.0);
		}

		public static SelAreaEdgeInfo Offset(SelAreaEdgeInfo edgeInfo, double offset)
		{
			XYZ startPoint = edgeInfo.StartPoint;
			XYZ endPoint = edgeInfo.EndPoint;
			if (edgeInfo.IsArc)
			{
				XYZ center = edgeInfo.Center;
				double num = edgeInfo.Radius + offset;
				XYZ xyz = (startPoint - center).Normalize() * num;
				XYZ xyz2 = (endPoint - center).Normalize() * num;
				XYZ startPoint2 = center + xyz;
				XYZ endPoint2 = center + xyz2;
				return new SelAreaEdgeInfo(startPoint2, endPoint2, edgeInfo.Bulge);
			}
			XYZ xyz3 = Geometry.RotateTo((endPoint - startPoint).Normalize(), Math.PI*.5, XYZ.BasisZ) * offset;
			XYZ startPoint3 = startPoint + xyz3;
			XYZ endPoint3 = endPoint + xyz3;
			return new SelAreaEdgeInfo(startPoint3, endPoint3, 0.0);
		}
	}
}
